/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>

// this should be enough
static char buf[65536] = {};
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
static char *code_format =
"#include <stdio.h>\n"
"int main() { "
"  unsigned result = %s; "
"  printf(\"%%u\", result); "
"  return 0; "
"}";

void gen_num(int *valid) {
  char str[33];
  
  int len = strlen(buf);
  uint32_t max = 9;
  uint32_t value = rand() % max + 1;

  sprintf(str, "%d", value);

  if ((len + strlen(str)) > 65535) {
    *valid = 0;
	return;
  }

  strcpy(buf + len, str);
}

void gen(char c, int *valid) {
  int len = strlen(buf);

  if ((len + 1) > 65535) {
    *valid = 0;
	return;
  }

	
  buf[len] = c;
  buf[len+1] = '\0';
}

void gen_rand_op(int *valid) {
  int len = strlen(buf);

  if ((len + 1) > 65535) {
    *valid = 0;
	return;
  }

  switch(rand()%4) {
	case 0:  buf[len] = '+'; break;
	case 1:  buf[len] = '-'; break;
	case 2:  buf[len] = '/'; break;
	case 3:  buf[len] = '*'; break;
   }
  
  buf[len+1] = '\0';
}

static void gen_rand_expr(int *valid) {
  if (*valid == 0) return;

  switch(rand()%3) {
    case 0: gen_num(valid); break; 
    case 1: gen('(', valid); gen_rand_expr(valid); gen(')', valid); break; 
	default: gen_rand_expr(valid); gen_rand_op(valid); gen_rand_expr(valid); break;
  }
}

int main(int argc, char *argv[]) {
  int seed = time(0);
  srand(seed);

  int loop = 1;
  if (argc > 1) {
    sscanf(argv[1], "%d", &loop);
  }

  int i;
  for (i = 0; i < loop; i ++) {
    int valid = 1;

	buf[0] = '\0';
    gen_rand_expr(&valid);

	if (!valid) {
	  // 发生溢出
	  i --;
	  continue;
	}

    sprintf(code_buf, code_format, buf);

    FILE *fp = fopen("/tmp/.code.c", "w");
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

	int ret = system("gcc /tmp/.code.c -o /tmp/.expr 2> /tmp/warning");
	if (ret != 0) continue;

	/* 处理除0的情况 */
	fp = fopen("/tmp/warning", "r");
	if (fp == NULL) assert(0);

	int flag = 1;
	char info[1024];
	while (fgets(info, 1024, fp) != NULL) { 
	  if (strstr(info, "division by zero") != NULL) {
		flag = 0;
		break;
	  }
	}

	// 有除0警告
	if (flag == 0) {
	  i --;
	  continue;
	} 

	fclose(fp);


    fp = popen("/tmp/.expr", "r");
    assert(fp != NULL);

    /*int result, processExitCode;*/
    int result;

    fscanf(fp, "%d", &result);
    pclose(fp);

	/*if (processExitCode != 0) {*/
	  /*// 发生除0异常*/
	  /*// printf("------------core dumped : i = %d\n", i);*/
	  /*i --;*/
	  /*continue;*/
	/*}*/
	// printf("------------normal : i = %d\n", i);

    printf("%u %s\n", result, buf);
  }
  return 0;
}
